<?php

//3rd party function used to improve drawing
//from php.net, where it is listed as an example
function image_line_thick($image, $x1, $y1, $x2, $y2, $color, $thick = 1)
{
    //this way it works well only for orthogonal lines
    //imagesetthickness($image, $thick);
    //return imageline($image, $x1, $y1, $x2, $y2, $color);
    if ($thick == 1) {
        return imageline($image, $x1, $y1, $x2, $y2, $color);
    }
    $t = $thick / 2 - 0.5;
    if ($x1 == $x2 || $y1 == $y2) {
        return imagefilledrectangle($image, round(min($x1, $x2) - $t), round(min($y1, $y2) - $t), round(max($x1, $x2) + $t), round(max($y1, $y2) + $t), $color);
    }
    $k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q
    $a = $t / sqrt(1 + pow($k, 2));
    $points = array(
        round($x1 - (1+$k)*$a), round($y1 + (1-$k)*$a),
        round($x1 - (1-$k)*$a), round($y1 - (1+$k)*$a),
        round($x2 + (1+$k)*$a), round($y2 - (1-$k)*$a),
        round($x2 + (1-$k)*$a), round($y2 + (1+$k)*$a),
    );
    imagefilledpolygon($image, $points, 4, $color);
    return imagepolygon($image, $points, 4, $color);
}

//
// A class representing a graphical line
//
class Line
{
    //Starting these at NULL so next_point can see if it is adding the first point or not
    private $lastx = NULL;
    private $lasty = NULL;

    public $color;
    public $image;
    public $thickness;

    function __construct($image, $color, $thickness = 2)
    {
        $this->color = $color;
        $this->image = $image;
        $this->thickness = $thickness;
    }

    function next_point($x,$y)
    {
        if ($this->lastx != NULL)
        {
            image_line_thick($this->image, $this->lastx, $this->lasty ,$x, $y, $this->color, $this->thickness); //don't draw if it's the first point
        }            
        $this->lastx = $x;$textcolor = imagecolorallocate($this->im, 0, 0, 0);
        $this->lasty = $y;
        return;
    }
}

//
// A class representing a Graph using GD
//
class Graph
{
    private $axes_offset = 25;
    private $xdim;          //The X and Y dimensions of the graphing area, in pixels
    private $ydim;
    private $xdiv = 1.0;    //specifies amount of pixels between graph values.  format() will set these to whatever will
    private $ydiv = 1.0;    //fill the specified image size.  defaults to 1:1
    private $xmin = 0.0;    //The highest and lowest value points on the graph.  The dimensions of the
    private $xmax = 1.0;    //Graph in the relevant units, not pixels.
    private $ymin = 0.0;
    private $ymax = 1.0;
    public $im;

    function __construct($x, $y) 
    {
        $this->xdim = $x - $this->axes_offset;
        $this->ydim = $y - $this->axes_offset;
        $this->im = imagecreate($x, $y);
        $this->bgcolor = imagecolorallocate($this->im, 240, 240, 240);            
    }
    //format takes the two numbers between which all of the X and/or Y values will fall, and
    //sets appropriate values for the other dimensions (xmax, xmin, xdiv...)
    function format($xmin, $xmax, $ymin, $ymax)
    {
        $this->xmin = $xmin; $this->xmax = $xmax;
        $this->ymin = $ymin; $this->ymax = $ymax;
        $this->xdiv = $this->xdim/($xmax - $xmin);
        $this->ydiv = $this->ydim/($ymax - $ymin);
    }
    function add_line($color, $points, $thickness)      //NOTE: as of yet, points[0] will not render.
    {                                                   //No idea why. Start at points[1] instead.                                                                
        $line = new Line($this->im, $color, $thickness=2);
        //For every point, we find the percent +X from xmin, and set the X coordinate the othe appropriate percent
        //over of the total X pixels of the graph
        foreach($points as $xval=>$yval)     //treat points as an array of Ys indexed by Xs (no X will have 2 Ys)
        {
            $xpoint = ($xval-$this->xmin) / ($this->xmax - $this->xmin);
            $xpoint = $this->xdim * $xpoint + $this->axes_offset;

            $ypoint = ($yval - $this->ymin)/($this->ymax - $this->ymin);
            $ypoint = $this->ydim - $this->ydim * $ypoint - $this->axes_offset;

            $line->next_point($xpoint,$ypoint + $this->axes_offset);
            imagefilledellipse($this->im, $xpoint, $ypoint + $this->axes_offset, 2, 8, $color);
        }
    }
    //Draws the axes of the graph.  Max and Min are the upper and lower labels for each
    //axis, and label is self-descriptive
    function axes($xmin, $xmax, $ymin, $ymax, $ylabel = "temp", $xlabel = "time")
    {
        $ycolor = imagecolorallocate($this->im,60,80,0);
        $xcolor = imagecolorallocate($this->im,30,0,80);

        image_line_thick($this->im, $this->axes_offset, 0, 
                        $this->axes_offset, $this->ydim, $ycolor, 2);
        imagestring($this->im, 1, 2, 4, $ymax, $ycolor);
        imagestring($this->im, 1, 2, $this->ydim - 4, $ymin, $ycolor);
        imagestringup($this->im, 3, 2, $this->ydim/2 + 16, $ylabel, $ycolor);

        image_line_thick($this->im, $this->axes_offset, $this->ydim, 
                        $this->xdim + $this->axes_offset, $this->ydim, $xcolor, 2);
        imagestring($this->im, 3, $this->xdim/2 - 4, $this->ydim + 6, $xlabel, $xcolor);
        imagestring($this->im, 1, $this->xdim - 30, $this->ydim + 10, $xmax, $xcolor);
        imagestring($this->im, 1, $this->axes_offset/2, $this->ydim + 10, $xmin, $xcolor);
    }

    function make_image($fname = "graph.png",$dir = "icons/")
    {
        imagepng($this->im, "{$dir}{$fname}");
        ImageDestroy($this->im);
    }
}

//Create an instance of the Graph class with the appropriate values
//To represent a given result set
function graph_results($x, $y, $results, $sensor_name = "")
{
    if($results)
    {
        $graph = new Graph($x,$y);
        $results = array_reverse($results, TRUE);
        $linecolor = imagecolorallocate($graph->im, 100, 0, 0);
        $first = reset($results);
        $last = end($results);
        $endday = strtotime($last[2]);
        $end_time = $endday + (strtotime($last[3]) - mktime(0,0,0));
        $startday = strtotime($first[2]);
        $start_time = $startday + (strtotime($first[3]) - mktime(0,0,0));
        $high = -10;
        $low  = 100;
        foreach($results as $res)
        {
            if($res[4] >= $high) 
            {
                $high = $res[4];
            }
            if($res[4] <= $low) 
            {
                $low = $res[4];
            }
        }
        $graph->format($start_time, $end_time, $low, $high);
        $points = array();
        foreach($results as $res)
        {
            $unixtime = strtotime($res[2]) + strtotime($res[3]) - mktime(0,0,0);
            $points[$unixtime] = $res[4];
        }
        $graph->add_line($linecolor,$points,3);
        $graph->axes(date("m/d h:i", $start_time), date("m/d h:i", $end_time), $low, $high);
        $graph->make_image($fname = $sensor_name."graph.png");
    }
}
?>
